﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.Resources;
using System.Runtime.InteropServices;
using System.Diagnostics;
using eeenno.ReaderEngine;
using eeenno.ReaderEngine.Objects;
using eeenno.ReaderEngine.Utilities;
using eeenno.ReaderEngine.Adapters;
using eeenno.SpeeedReaderUI.NativeWebBrowser.Windows.Forms;
using mirabyte.Mobile.TouchControls;
using mirabyte.Mobile.TouchControls.Dialogs;

namespace eeenno.SpeeedReaderUI.Forms
{
    public partial class MainForm : Form
    {
        //trial length in days
        private int TRIAL_LENGTH = 10;

        //flags used for different program statuses
        private bool _currently_refreshing;
        private bool _first_refresh_run;
        private bool _copying_cache;
        private volatile bool _abort_refresh;
        private volatile bool _is_ui_processing;

        private delegate void _toggleWaitCursorCallback(bool enable);
        private delegate void _addTagCallback(Tag info);
        private delegate void _addSubscriptionCallback(Subscription info);
        private delegate void _addArticleCallback(Article info);
        private delegate void _addArticleCallback2(Article info);
        private delegate void _updateListBoxCallback(bool goingBack);
        private delegate void _updateListBoxCallback2(bool keep_selection);
        private delegate void _updateStatusLabelCallback(string title);
        private delegate void _toggleRefresh(bool enable);
        private delegate void _refreshListCallback();
        private delegate void _toggleStarArticleCallback(bool enable);
        private delegate void _closeBrowserCallback(object ob);
        private delegate void _openBrowserCallback(object ob);
        private delegate void _loadListBoxCallback();
        private delegate void _clearCallback(bool all_lists);
        private delegate void _toggleCheckItem();
        private delegate void _updateRefreshLabel(string progress);
        private delegate void _toggleSubtextDelegate(bool enable);
        private delegate void _toggleBackButtonDelegate();
        private delegate void _toggleMainListBoxDelegate(bool enable);
        private delegate void _toggleCachingMenuDelegate(bool enable);
        private delegate void _focusListBoxDelegate();

        private view_state _currently_viewing;
        private enum view_state 
        { 
            tags = 0, 
            subscriptions, 
            articles, 
            reading, 
            browser, 
            starred, 
            shared, 
            tag_reading,
            search
        };

        private enum icon_type
        {
            unread_tag = 0,
            read_tag,
            sub,
            unread_art,
            read_art,
            star
        };

        //global variables for thread access
        private int _tag_index;
        private int _sub_index;
        private int _art_index;
        private int _selected_item_index;
        private int _selected_index;
        private string _t_html = null;

        //queue for TouchList items (for pagination)
        private List<TouchListBox.TouchListItem> _list_items = null;
        private int _page;
        private int _max_pages;

        Thread _populate_thread = null;
        Thread _refresh_all_process = null;

        System.Threading.Timer _refresh_timer = null;

        //saving current page location
        private int _tag_page;
        private int _sub_page;
        private bool _going_back;

        public MainForm()
        {
            LicenseManager.Instance.LicenseKey = "";
            InitializeComponent();           
            if (Settings.Initialize())
            {
                if (Settings.first_run)
                {
                    MainForm.DisplayMessageBox("Speeed Reader uses a lot data while downloading feeds. " +
                        "Please check that your device has an appropriate data plan or use Wi-Fi. " +
                        "Data charges while roaming can be particularly high. Press OK to continue.");
#if !Marketplace
                    RegistrationManager.CreateFirstInstallFile();
#endif
                    Settings.first_run = false;
                }
#if Marketplace
                DialogResult reg_result = DialogResult.OK;
#endif
#if !Marketplace
                DialogResult reg_result = DialogResult.Cancel;
                if (!RegistrationManager.IsRegistered())
                {
                    DateTime toi = RegistrationManager.GetNotifierFileCreationTime();//new DateTime(Settings.toi);
                    TimeSpan duration = new TimeSpan(DateTime.Now.Ticks - toi.Ticks);
                    //if time since installation has exceed the trial length, force a registration
                    if (duration.Days > TRIAL_LENGTH)
                    {
                        RegisterForm register_form = new RegisterForm();
                        reg_result = register_form.ShowDialog();
                    }
                    else
                    {
                        reg_result = DialogResult.OK;
                    }
                }
                else
                {
                    reg_result = DialogResult.OK;
                }
#endif
                //if result = ok then the registration succeeded or trial is still active
                if (reg_result == DialogResult.OK)
                {
                    Security.Initialize();
                    SpeeedReader.InitializeStorageCardPath();

                    SetupApp();
                    LoginForm login_form = new LoginForm();
                    DialogResult result = login_form.ShowDialog();
                    if (result == DialogResult.Yes)
                    {
                        //hack to make browser show after a cached refresh - i dunno lol
                        _t_html = "<b>test</b>";
                        ShowBrowserCallback(null);
                        CloseBrowserCallback(null);
                        login_form.Dispose();
                        _currently_viewing = view_state.tags;
                        ConfigureForm(true);
                        _populate_thread = ThreadFactory.GetUIThread("PopulateForm", PopulateForm);
                        _populate_thread.Start();
                        ToggleOfflineModeForm(false);
                        menuItem_show_reading_list.Checked = Settings.show_reading_list_at_startup;
                        ConfigureTimer(false);
                    }
                    else
                    {
                        this.Close();
                    }
                }
                //trial is no longer active or registration failed
                else
                {
                    DisplayMessageBox("Please purchase a registration key to continue use of Speeed Reader");
                    this.Close();
                }
            }
            else
            {
                DisplayMessageBox("There has been an error loading the settings from the configuration file, please re-install Speeed Reader.");
                this.Close();
            }
        }

        public void SetupApp()
        {
            ServicePointManager.Expect100Continue = false;
            ServicePointManager.DefaultConnectionLimit = 16;
            ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();
            ThreadPool.SetMaxThreads(16, 16);
            GlassDialog.Font = new Font("Tahoma", 9F, FontStyle.Regular);
        }

        #region Methods for configuring application

        public void ConfigureTimer(bool deactivate)
        {
            if(deactivate)
            {
                if (_refresh_timer != null)
                {
                    _refresh_timer.Dispose();
                    _refresh_timer = null;
                }
            }
            else if (Settings.refresh_duration > 0 && !Settings.offline_mode_enabled)
            {
                int interval = Settings.refresh_duration * 60 * 1000;
                if (_refresh_timer != null)
                {
                    _refresh_timer.Dispose();
                    _refresh_timer = null;
                }
                _refresh_timer = new System.Threading.Timer(RefreshProcess, null, interval, interval);
            }            
        }

        public void ConfigureForm(bool configure_theme)
        {
            if (configure_theme)
            {
                ConfigureTheme();
            }
            if (Settings.show_icons)
            {
                main_listBox.ShowIcons = true;
                main_listBox.SpaceLeft = 0;
            }
            else
            {
                main_listBox.ShowIcons = false;
                main_listBox.SpaceLeft = 5;
            }            
            switch (Settings.item_size)
            {
                case 0:
                    main_listBox.ItemHeight = 34;                    
                    break;
                case 1:
                    main_listBox.ItemHeight = 55;
                    break;
                default:
                    main_listBox.ItemHeight = 55;
                    break;
            }

            main_listBox.Width = this.Width;
            if (Settings.show_progress_bar)
            {
                panel_status.Show();
                main_listBox.Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top | AnchorStyles.Bottom;
                main_listBox.Height = this.Height - panel_status.Height;
            }
            else
            {
                panel_status.Hide();
                main_listBox.Dock = DockStyle.Fill;
            }
        }

        private void SetColors(Color backColor, Color itemBackgroundColor, Color itemBackgroundColor2,
            Color textColor, Color textColorSelected, Color subTextColor, Color subTextColorSelected,
            Color itemBackgroundColorSelected)
        {
            main_listBox.BackColor = backColor;
            main_listBox.ItemBackgroundColor = itemBackgroundColor;
            main_listBox.ItemBackgroundColor2 = itemBackgroundColor2;
            main_listBox.TextColor = textColor;
            main_listBox.TextColorSelected = textColorSelected;
            main_listBox.SubTextColor = subTextColor;
            main_listBox.SubTextColorSelected = subTextColorSelected;
            main_listBox.ItemBackgroundColorSelected = itemBackgroundColorSelected;

            panel_status.BackColor = label_program_status.BackColor = label_refresh_status.BackColor = backColor;
            label_program_status.ForeColor = label_refresh_status.ForeColor = textColor;
        }

        private void ConfigureTheme()
        {
            switch(Settings.theme)
            {
                case 0:
                    SetColors(Color.White, Color.White, Color.Gainsboro, Color.Black, Color.White,
                        Color.Gray, Color.White, Color.Crimson);                                      
                    break;
                case 1:
                    SetColors(Color.Black, Color.Black, Color.DimGray, Color.White, Color.Black,
                        Color.WhiteSmoke, Color.Black, Color.DarkOrange); 
                    break;
                case 2:
                    SetColors(Color.Coral, Color.Coral, Color.LightSalmon, Color.White, Color.White,
                        Color.White, Color.White, Color.Teal);                    
                    break;
                default:
                    SetColors(Color.White, Color.White, Color.Gainsboro, Color.Black, Color.White,
                        Color.Gray, Color.White, Color.Crimson);  
                    break;
            }
        }
        #endregion

        #region control action handlers

        private void menuItem_search_Click(object sender, EventArgs e)
        {
            view_state state = _currently_viewing;
            _currently_viewing = view_state.search;
            ToggleCheckItem();
            SearchForm search_form = new SearchForm();
            if (search_form.ShowDialog() == DialogResult.OK)
            {
                string search_string = search_form.search_string;
                ThreadFactory.DoWork(SearchArticles, search_string);
                ToggleBackButtonCallback();
            }
            else
            {
                _currently_viewing = state;
            }

            search_form.Dispose();
        }

        private void MainForm_Closing(object sender, CancelEventArgs e)
        {
            if (_populate_thread != null)
            {
                _populate_thread.Abort();
            }
            if (_refresh_all_process != null)
            {
                _refresh_all_process.Abort();
            }            
        }

        private void menuItem_broadcast_Click(object sender, EventArgs e)
        {
            ThreadFactory.DoWork(SpeeedReader.MarkItemBroadcast, ArticleFromView().id);
            DisplayMessageBox("The was article broadcasted");
        }

        private void menuItem_mark_unread_Click(object sender, EventArgs e)
        {
            if (main_listBox.SelectedIndex > -1)
            {
                Article article = ArticleFromView();
                if (article.id.Length > 0)
                {
                    article.unread = true;
                    ThreadFactory.DoWork(MarkStoredArticleUnread, article.id);
                    main_listBox.Items[_art_index].ItemIconAlpha = GetIcon(icon_type.unread_art);
                    UpdateListBoxCallback2(true);
                }
            }
            else
            {
                DisplayMessageBox("Please select an article to mark unread");
            }
        }

        private void menuItem_show_all_Click(object sender, EventArgs e)
        {
            ThreadFactory.DoWork(PopulateWithReadingListArticles);         
        }

        private void menuItem_show_starred_Click(object sender, EventArgs e)
        {
            ThreadFactory.DoWork(PopulateWithStarredArticles);
        }

        private void menuItem_show_tags_Click(object sender, EventArgs e)
        {
            ThreadFactory.DoWork(PopulateWithTags);
        }

        private void menuItem_show_broadcast_Click(object sender, EventArgs e)
        {
            ThreadFactory.DoWork(PopulateWithBroadcastArticles);
        }

        private void menuItem_email_Click(object sender, EventArgs e)
        {
            if (main_listBox.SelectedIndex > -1 || webBrowser_article.Visible)
            {
                string[] info = GetArticleInfoToShare();
                if (info != null && info[0].Length > 0)
                {
                    ThreadFactory.DoWork(CreateEmail, info);
                }
            }
            else
            {
                DisplayMessageBox("Please select an article share");
            }
        }

        private void menuItem_sms_Click(object sender, EventArgs e)
        {
            if (main_listBox.SelectedIndex > -1 || webBrowser_article.Visible)
            {
                string[] info = GetArticleInfoToShare();
                if (info != null && info.Length > 0)
                {
                    ThreadFactory.DoWork(CreateSms, info);
                }
            }
            else
            {
                DisplayMessageBox("Please select an article share");
            }

        }

        private void menuItem_twitter_Click(object sender, EventArgs e)
        {
            if (Settings.twitter_username.Length > 0 && Settings.twitter_password.Length > 0)
            {
                if (main_listBox.SelectedIndex > -1 || webBrowser_article.Visible)
                {
                    TwitterForm twitter_form = new TwitterForm(ArticleFromView().url, ArticleFromView().title);                    
                    if (twitter_form != null)
                    {
                        twitter_form.Show();
                    }
                }
                else
                {
                    DisplayMessageBox("Please select a article to Tweet");
                }
            }
            else
            {
                DisplayMessageBox("Enter your Twitter account information in Settings");
            }
        }

        private void menuItem_mark_read_Click(object sender, EventArgs e)
        {
            if (main_listBox.SelectedIndex > -1 && main_listBox.Items[main_listBox.SelectedIndex].Name.Length > 0)
            {
                _art_index = int.Parse(main_listBox.Items[main_listBox.SelectedIndex].Name);
            }
            else if (main_listBox.SelectedIndex > -1 && main_listBox.Items[main_listBox.SelectedIndex].Name.Length == 0)
            {
                //_art_index = main_listBox.SelectedIndex;
                return;
            }
            else
            {
                _art_index = main_listBox.SelectedIndex;
            }
            switch (_currently_viewing)
            {
                case view_state.tags:
                    ThreadFactory.DoWork(MarkTagItemAsRead);
                    ThreadFactory.DoWork(MarkTagAsRead);     
                    break;
                case view_state.subscriptions:
                    ThreadFactory.DoWork(MarkSubItemAsRead);
                    ThreadFactory.DoWork(MarkSubAsRead);
                    break;
                case view_state.articles:
                    ThreadFactory.DoWork(MarkArticleAsRead);                  
                    break;
            }            
        }

        private void menuItem_about_Click(object sender, EventArgs e)
        {
            AboutForm about_form = new AboutForm(WebManager.bytes_transferred);
            about_form.Show();
        }
#if !Marketplace
        private void menuItem_update_Click(object sender, EventArgs e)
        {
            ThreadFactory.DoWork(CheckForUpdate, true);
        }
#endif

        private void menuItem_refresh_Click(object sender, EventArgs e)
        {
            if (!_currently_refreshing)
            {
                _refresh_all_process = null;
                switch(_currently_viewing)
                {
                    case view_state.tags:
                        _refresh_all_process = ThreadFactory.GetThread("RefreshAll", RefreshAll);
                        _refresh_all_process.Start();
                        break;
                    case view_state.subscriptions:
                        _refresh_all_process = ThreadFactory.GetThread("RefreshTag", RefreshTag);
                        _refresh_all_process.Start();
                        break;
                    case view_state.articles:
                        _refresh_all_process = ThreadFactory.GetThread("RefreshSub", RefreshSubscription);
                        _refresh_all_process.Start();
                        break;
                    case view_state.shared:
                        _refresh_all_process = ThreadFactory.GetThread("RefreshShared", RefreshShared);
                        _refresh_all_process.Start();
                        break;
                    case view_state.starred:
                        _refresh_all_process = ThreadFactory.GetThread("RefreshStarred", RefreshStarred);
                        _refresh_all_process.Start();
                        break;
                    case view_state.reading:
                        _refresh_all_process = ThreadFactory.GetThread("RefreshReadingList", RefreshReadingList);
                        _refresh_all_process.Start();
                        break;
                }
            }
            else
            {        
                _abort_refresh = true;
                ToggleRefresh(true);
                _currently_refreshing = false;
                ConfigureTimer(false); 
                UpdateRefreshLabelCallback("Canceling...");
            }
        }

        private void menuItem_exit_Click(object sender, EventArgs e)
        {
#if !Hopper
            this.Close();
#endif
        }

        private void menuItem_appearance_Click(object sender, EventArgs e)
        {
            int page_size = Settings.page_size;
            int item_size = Settings.item_size;
            int theme = Settings.theme;
            SettingsAppearanceForm form = new SettingsAppearanceForm();
            if (form.ShowDialog() == DialogResult.OK)
            {
                ConfigureForm((theme != Settings.theme));
                if (page_size != Settings.page_size)
                {
                    ChangePage(null);
                }
                if (item_size != Settings.item_size)
                {
                    UpdateForm();
                }
                if (!Settings.use_smaller_list_font && _currently_viewing == (view_state.tags | view_state.subscriptions))
                {
                    main_listBox.Font = new System.Drawing.Font("Tahoma", 10F, System.Drawing.FontStyle.Regular);
                }
                else
                {
                    main_listBox.Font = new System.Drawing.Font("Tahoma", 8F, System.Drawing.FontStyle.Bold);
                }
                main_listBox.UpdateList();
            }
            form.Dispose();
        }

        private void menuItem_behavior_Click(object sender, EventArgs e)
        {
            int duration = Settings.refresh_duration;
            bool hide = Settings.hide_read_items;
            SettingsBehaviorForm form = new SettingsBehaviorForm();

            if (form.ShowDialog() == DialogResult.OK)
            {
                //only reset timer if a change was made to the refresh duration
                if (duration != Settings.refresh_duration)
                {
                    ConfigureTimer(true);
                    ConfigureTimer(false);
                }

                if (hide = true && hide != Settings.hide_read_items)
                {
                    UpdateForm();
                }
            }
            form.Dispose();
        }

        private void menuItem_caching_Click(object sender, EventArgs e)
        {
            bool cache_en = Settings.caching_enabled;
            bool cache_on_mem = Settings.store_cache_on_memory_card;
            string cache_loc = Settings.cache_path;

            SettingsCacheForm form = new SettingsCacheForm();
            DialogResult result = form.ShowDialog();
            if (result == DialogResult.Cancel)
            {
                Settings.store_cache_on_memory_card = cache_on_mem;
                Settings.caching_enabled = cache_en;
                Settings.WriteSettings();
            }
                /*
            else if (result == DialogResult.OK)
            {
                if (Settings.caching_enabled)
                {
                    if (cache_loc != Settings.cache_path)
                    {
                        ThreadFactory.DoWork(CopyCache, cache_loc + Settings.username);
                    }
                }
            }*/
            form.Dispose();
        }

        private void menuItem_connectivity_Click(object sender, EventArgs e)
        {
            bool offline_mode = Settings.offline_mode_enabled;
            SettingsConnectivityForm form = new SettingsConnectivityForm();
            form.ShowDialog();
            form.Dispose();
            if (offline_mode != Settings.offline_mode_enabled)
            {
                ToggleOfflineModeForm(true);
            }
        }

        private void menuItem_social_Click(object sender, EventArgs e)
        {
            SettingsSocialForm form = new SettingsSocialForm();
            form.ShowDialog();
            form.Dispose();
        }

        private void tag_item_click(int index)
        {
            _tag_index = index;
            ThreadFactory.DoWork(PopulateWithSubscriptions);
        }

        private void subscription_item_click(int index)
        {            
            _sub_index = _selected_item_index;
            ThreadFactory.DoWork(PopulateWithArticles);
        }

        private void article_item_click(int index)
        {
            //temporary hack for viewing search articles
            //if (_currently_viewing == view_state.search)
            //{
            //    _art_index = index;
            //}
            //else
            {
                _art_index = _selected_item_index;
            }
            Article current_article = ArticleFromView();            

            if (Settings.always_open_in_browser)
            {
                menuItem_open_in_browser_Click(this, EventArgs.Empty);
            }
            else
            {               
                menuItem_search.Enabled = menuItem_view.Enabled = false;
                _t_html = ProcessHTML(current_article.summary);
                ShowBrowserCallback(null);
                _currently_viewing = view_state.browser;
            }
            //we are reading a reading list article, mark the article in its specified feed as read
            if (_sub_index == 0)
            {
                ThreadFactory.DoWork(MarkStoredArticleRead, current_article.id);
            }
            //do not mark read if already marked read
            if (current_article.unread)
            {
                current_article.unread = false;
                ThreadFactory.DoWork(MarkArticleRead);            
            }            
            //do not mark (icon) as read if its starred
            if (!current_article.starred)
            {
                int temp = index;
                if (_page > 0)
                {
                    temp -= (_page * Settings.page_size - 1);
                }
                if (temp <= Settings.page_size)
                {
                    MarkArticleItemRead(temp);
                }
            }
            webBrowser_article.Focus();
        }

        private void main_listBox_ItemClick(object sender, int SelectedIndex)
        {
            try
            {
                //clean up the populate thread
                if (_populate_thread != null)
                {
                    _populate_thread = null;
                }
                _selected_index = SelectedIndex;
                if (main_listBox.Items[SelectedIndex].Name.Length > 0 && _currently_viewing != view_state.search)
                {
                    _selected_item_index = int.Parse(main_listBox.Items[SelectedIndex].Name);
                }
                //if the first item (sometimes the prev page item) is clicked and we aren't on the first page
                if (SelectedIndex == 0 && _page > 0)
                {
                    //go to the previous page
                    _page--;
                    ThreadFactory.DoWork(ChangePage);
                }
                //if the last time (sometimes the next page item) is click and we aren't on the last paeg
                else if (SelectedIndex == (main_listBox.Items.Count - 1) && _page < (_max_pages - 1))
                {
                    //go to the next page
                    _page++;
                    ThreadFactory.DoWork(ChangePage);
                }
                //if we are on the last page and the last item is clicked (download more button)
                else if (SelectedIndex == (main_listBox.Items.Count - 1) && _page == (_max_pages - 1)
                    && (_currently_viewing == view_state.tag_reading || _currently_viewing == view_state.articles)
                    /*&& Settings.download_read_articles*/)
                {
                    //download more items
                    ThreadFactory.DoWork(DownloadMoreArticles);
                }
                else
                {
                    if (_page > 0)
                    {
                        SelectedIndex += _page * Settings.page_size - 1;
                    }
                    switch (_currently_viewing)
                    {
                        case view_state.tags:
                            tag_item_click(SelectedIndex);
                            break;
                        case view_state.subscriptions:
                            subscription_item_click(SelectedIndex);
                            break;
                        case view_state.articles:
                            article_item_click(SelectedIndex);
                            break;
                        case view_state.reading:
                            article_item_click(SelectedIndex);
                            break;
                        case view_state.starred:
                            article_item_click(SelectedIndex);
                            break;
                        case view_state.shared:
                            article_item_click(SelectedIndex);
                            break;
                        case view_state.tag_reading:
                            article_item_click(SelectedIndex);
                            break;
                        case view_state.search:
                            article_item_click(SelectedIndex);
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (Exception e)
            {
            }
        }        

        private void menuItem_mark_star_Click(object sender, EventArgs e)
        {
            Article article = ArticleFromView();
            if (article.id.Length > 0)
            {                
                article.starred = true;
                ThreadFactory.DoWork(MarkStoredArticleStar, article.id);
                main_listBox.Items[_art_index].ItemIconAlpha = GetIcon(icon_type.star);
                UpdateListBoxCallback2(true);
            }            
        }

        private void menuItem_open_in_browser_Click(object sender, EventArgs e)
        {
            string url = ArticleFromView().url;         

            try
            {
                if (url.Length > 0)
                {
                    System.Diagnostics.Process.Start(url, String.Empty);
                }
            }
            catch (Exception error)
            {
                try
                {
                    System.Diagnostics.Process.Start("iexplore.exe", url);
                }
                catch(Exception e3)
                {
                    DisplayMessageBox("There was an error opening your default browser");
                }
            }
        }

        private void MainForm_KeyDown(object sender, KeyEventArgs e)
        {            
            if ((e.KeyCode == System.Windows.Forms.Keys.Up))
            {
                // Up
            }
            if ((e.KeyCode == System.Windows.Forms.Keys.Down))
            {
                // Down
            }
            if ((e.KeyCode == System.Windows.Forms.Keys.Left))
            {
                BackAction(sender, EventArgs.Empty);
            }
            if ((e.KeyCode == System.Windows.Forms.Keys.Right))
            {
                if (main_listBox.Focused && main_listBox.SelectedIndex > -1)
                {
                    main_listBox_ItemClick(sender, main_listBox.SelectedIndex);
                }
            }
            if ((e.KeyCode == System.Windows.Forms.Keys.Enter))
            {
                // Enter
            }
        }

        #endregion

        #region methods that manipulate data

#if !Marketplace
        private void CheckForUpdate(Object stateInfo)
        {
            bool user_initiated = (bool)stateInfo;
            if (user_initiated)
            {
                ToggleWaitCursorCallback(true);
            }
            float version = UpdateManager.IsUpdateAvailable();
            if (version > -1.0)
            {
                if (DisplayYesNoMessageBox("Speeed Reader v" + version +
                    " is available.  Do you want to download the update?") == 1)
                {
                    ToggleWaitCursorCallback(true);
                    string update_path = UpdateManager.DownloadUpdate();
                    ToggleWaitCursorCallback(false);
                    if (update_path != string.Empty)
                    {
                        if (DisplayYesNoMessageBox("The update has been downloaded.  Do you want to install it now?") == 1)
                        {
                            System.Diagnostics.Process.Start(update_path, string.Empty);
                        }
                        else
                        {
                            DisplayMessageBox("The update has been downloaded to " + Settings.application_directory);
                        }
                    }
                }
                else
                {
                    if (user_initiated)
                    {
                        ToggleWaitCursorCallback(false);
                    }
                }
            }
            else
            {
                if (user_initiated)
                {
                    ToggleWaitCursorCallback(false);
                    DisplayMessageBox("An update is not available at this time");
                }
            }
        }
#endif

        private void CopyCache(Object stateInfo)
        {
            _copying_cache = true;
            ToggleWaitCursorCallback(true);
            SpeeedReader.CopyCache((string)stateInfo);
            ToggleWaitCursorCallback(false);
            _copying_cache = false;
            DisplayMessageBox("Article cache moved");
        }

        private Article ArticleFromView()
        {
            if (!webBrowser_article.Visible)
            {
                if (/*_currently_viewing != view_state.search && */main_listBox.SelectedIndex > -1 && main_listBox.Items[main_listBox.SelectedIndex].Name.Length > 0)
                {
                    _art_index = int.Parse(main_listBox.Items[main_listBox.SelectedIndex].Name);
                }
                else if(_currently_viewing != view_state.search)
                {
                    return new Article();
                }
            }
            switch (_currently_viewing)
            {
                case view_state.tags:
                    break;
                case view_state.subscriptions:
                    break;
                case view_state.articles:
                    return SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.
                        Get(_art_index);
                case view_state.reading:
                    return SpeeedReader.reading.Get(_art_index);
                case view_state.browser:
                    if (menuItem_show_tags.Checked)
                        return SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.
                            Get(_art_index);
                    else if (menuItem_show_reading_list.Checked)
                        return SpeeedReader.reading.Get(_art_index);
                    else if (menuItem_show_broadcast.Checked)
                        return SpeeedReader.shared.Get(_art_index);
                    else if (menuItem_show_starred.Checked)
                        return SpeeedReader.starred.Get(_art_index);
                    else
                        return SpeeedReader.search_results.Get(_art_index);
                case view_state.starred:
                    return SpeeedReader.starred.Get(_art_index);
                case view_state.shared:
                    return SpeeedReader.shared.Get(_art_index);
                case view_state.tag_reading:
                    return SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.
                        Get(_art_index);
                case view_state.search:
                    return SpeeedReader.search_results.Get(_art_index);
            }
            
            return new Article();
        }

        private void PreRefresh(bool refreshing_all)
        {
            if (refreshing_all)
            {
                _first_refresh_run = true;
            }
            _currently_refreshing = true;
            ConfigureTimer(true); //deactive the timer
            ToggleRefresh(false);
        }

        private void PostRefresh()
        {
            ToggleRefresh(true);
            _abort_refresh = _currently_refreshing = false;
            UpdateRefreshLabelCallback("Last Refresh: " + DateTime.Now.ToShortTimeString());
            ConfigureTimer(false);
        }

        private void RefreshTag()
        {
            ToggleWaitCursorCallback(true);
            PreRefresh(false);
            ToggleCachingMenuCallback(false);
            int sub_count = SpeeedReader.tags.Get(_tag_index).subscriptions.Count;
            int current = 0;
            double progress = 0.0;
            UpdateRefreshLabelCallback("Refreshing..." + progress.ToString("0.#") + "%");
            for (int j = 0; j < SpeeedReader.tags.Get(_tag_index).subscriptions.Count && !_abort_refresh; j++)
            {
                //if not, get them
                if (SpeeedReader.tags.Get(_tag_index).subscriptions.Get(j).article_count == 0)//.articles == null)
                {
                    if (Settings.caching_enabled && SpeeedReader.DoesCacheExist())
                    {
                        SpeeedReader.tags.Get(_tag_index).subscriptions.Set(j,
                        SpeeedReader.ImportSubscription(SpeeedReader.tags.Get(_tag_index).subscriptions.Get(j).title));
                        SpeeedReader.tags.Get(_tag_index).subscriptions.Get(j).RefreshArticles(false);
                    }
                    else
                    {
                        SpeeedReader.tags.Get(_tag_index).subscriptions.Get(j).RefreshArticles(true);
                    }
                }
                //if the articles have already been loaded, just refresh them
                else
                {
                    SpeeedReader.tags.Get(_tag_index).subscriptions.Get(j).RefreshArticles(false);
                }
                current++;
                progress = ((double)current / (double)sub_count) * 100.0;
                UpdateRefreshLabelCallback("Refreshing..." + progress.ToString("0.#") + "%");
            }
            SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshUnreadCount();
            SpeeedReader.tags.Get(_tag_index).RefreshUnreadCount();
            UpdateForm();
            ToggleCachingMenuCallback(true);
            PostRefresh();
            ToggleWaitCursorCallback(false);
        }

        private void RefreshSubscription()
        {
            ToggleWaitCursorCallback(true);
            PreRefresh(false);
            Subscription sub = SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index);
            UpdateRefreshLabelCallback("Refreshing " + sub.title);            
            //if not, get them
            if (!sub.articles_loaded)
            {
                if (Settings.caching_enabled && SpeeedReader.DoesCacheExist())
                {
                    SpeeedReader.tags.Get(_tag_index).subscriptions.Set(_sub_index,
                        SpeeedReader.ImportSubscription(sub.title));
                    SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshArticles(false);
                }
                else
                {
                    SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshArticles(true);
                }
            }                
            //if the articles have already been loaded, just refresh them
            else
            {
                SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshArticles(false);
            }
            SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshUnreadCount();
            UpdateForm();
            PostRefresh();
            ToggleWaitCursorCallback(false);
        }

        private void RefreshStarred()
        {
            PreRefresh(false);
            UpdateRefreshLabelCallback("Refreshing Starred List");
            SpeeedReader.RefreshStarredList();
            PostRefresh();
        }

        private void RefreshShared()
        {
            PreRefresh(false);
            UpdateRefreshLabelCallback("Refreshing Shared List");
            SpeeedReader.RefreshSharedList();
            PostRefresh();
        }

        private void RefreshReadingList()
        {
            PreRefresh(false);
            UpdateRefreshLabelCallback("Refreshing Reading List");
            SpeeedReader.RefreshReadingList(_first_refresh_run);
            PostRefresh();
        }

        private void RefreshAll()
        {
            PreRefresh(true);
            int sub_count = SpeeedReader.tags.subscription_count;
            int current = 0;
            double progress = 0.0;
            UpdateRefreshLabelCallback("Refreshing..." + progress.ToString("0.#") + "%");
            for (int i = 0; i < SpeeedReader.tags.Count; i++)
            {               
                for (int j = 0; j < SpeeedReader.tags.Get(i).subscriptions.Count && !_abort_refresh; j++)
                {
                    //if not, get them
                    if (SpeeedReader.tags.Get(i).subscriptions.Get(j).article_count == 0)
                    {
                        if (Settings.caching_enabled && SpeeedReader.DoesCacheExist())
                        {
                            SpeeedReader.tags.Get(i).subscriptions.Set(j,
                                SpeeedReader.ImportSubscription(SpeeedReader.tags.Get(i).subscriptions.Get(j).title));
                            SpeeedReader.tags.Get(i).subscriptions.Get(j).RefreshArticles(false);
                        }
                        else
                        {
                            SpeeedReader.tags.Get(i).subscriptions.Get(j).RefreshArticles(true);
                        }                        
                    }
                    //if the articles have already been loaded, just refresh them
                    else
                    {
                        SpeeedReader.tags.Get(i).subscriptions.Get(j).RefreshArticles(false);
                    }
                    current++;
                    progress = ((double)current / (double)sub_count) * 100.0;
                    SpeeedReader.tags.Get(i).subscriptions.Get(j).RefreshUnreadCount();
                    UpdateRefreshLabelCallback("Refreshing..." + progress.ToString("0.#") + "%");
                }
                SpeeedReader.tags.Get(i).RefreshUnreadCount();
            }           
            if (!_abort_refresh)
            {
                RefreshReadingList();
                RefreshShared();
                RefreshStarred();
                if (Settings.caching_enabled)
                {
                    UpdateRefreshLabelCallback("Caching data...");
                }
                UpdateForm();
                if (!_copying_cache)
                {
                    SpeeedReader.CacheData();
                }
            }
            PostRefresh();
        }

        private void PopulateForm()
        {            
            ToggleWaitCursorCallback(true);                      
            if (SpeeedReader.PopulateLists())
            {                
                ToggleWaitCursorCallback(false);
                _list_items = new List<TouchListBox.TouchListItem>();  
                if(Settings.show_reading_list_at_startup)
                {
                    _page = 0;
                    menuItem_show_all_Click(this, EventArgs.Empty);                    
                }
                else
                {
                    menuItem_show_tags_Click(this, EventArgs.Empty);
                }
            }
            else
            {
                DisplayMessageBox("There are no feeds to display.  Please add subscriptions to your Google Reader account.");
                ToggleWaitCursorCallback(false);
            }
#if !Marketplace
            if (Settings.check_for_update_at_login)
            {
                CheckForUpdate(false);
            }
#endif
        }       

        private void UpdateForm()
        {
            switch (_currently_viewing)
            {
                case view_state.tags:
                    ThreadFactory.DoWork(UpdateTags);
                    break;
                case view_state.subscriptions:
                    ThreadFactory.DoWork(UpdateSubscriptions);                   
                    break;
                case view_state.articles:
                    ThreadFactory.DoWork(UpdateArticles);
                    break;
                case view_state.reading:
                    ThreadFactory.DoWork(UpdateReadingListArticles);
                    break;
                case view_state.browser:
                    if (menuItem_show_reading_list.Checked)
                    {
                        ThreadFactory.DoWork(UpdateReadingListArticles);                        
                    }
                    else if (menuItem_show_broadcast.Checked)
                    {
                        ThreadFactory.DoWork(UpdateBroadcastArticles);  
                    }
                    else if (menuItem_show_starred.Checked)
                    {
                        ThreadFactory.DoWork(UpdateStarredArticles);  
                    }
                    else if(menuItem_show_tags.Checked)
                    {
                        ThreadFactory.DoWork(UpdateArticles);
                    }
                    break;
                case view_state.starred:
                    ThreadFactory.DoWork(UpdateStarredArticles);
                    break;
                case view_state.shared:
                    ThreadFactory.DoWork(UpdateBroadcastArticles);
                    break;
                case view_state.tag_reading:
                    ThreadFactory.DoWork(UpdateArticles);
                    break;
                default:
                    break;
            }
        }

        private void UpdateTags(Object stateInfo)
        {
            ClearCallback(true);            
            for (int i = 0; i < SpeeedReader.tags.Count; i++)
            {
                SpeeedReader.tags.Get(i).RefreshUnreadCount();
                SpeeedReader.tags.Get(i).index = i;
                AddTagCallback(SpeeedReader.tags.Get(i));
            }
            LoadListBoxCallback();
            UpdateListBoxCallback2(true);
        }

        private void UpdateSubscriptions(Object stateInfo)
        {
            ClearCallback(true);
            for (int i = 0; i < SpeeedReader.tags.Get(_tag_index).subscriptions.Count; i++)
            {
                SpeeedReader.tags.Get(_tag_index).subscriptions.Get(i).index = i;
                AddSubscriptionCallback(SpeeedReader.tags.Get(_tag_index).subscriptions.Get(i));
            }
            LoadListBoxCallback();
            UpdateListBoxCallback2(true);
        }

        private void UpdateReadingListArticles(Object stateInfo)
        {
            ClearCallback(true);
            for (int i = 0; i < SpeeedReader.reading.Count; i++)
            {
                SpeeedReader.reading.Get(i).index = i;
                AddArticleCallback2(SpeeedReader.reading.Get(i));
            }
            LoadListBoxCallback();
            UpdateListBoxCallback2(true);
        }

        private void UpdateArticles(Object stateInfo)
        {
            ClearCallback(true);
            {
                for (int i = 0; i < SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.Count; i++)
                {
                    SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.Get(i).index = i;
                    //if article is from a reading list    
                    if (SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).is_reading_list)
                    {
                        AddArticleCallback2(SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.Get(i));
                    }
                    //if not
                    else
                    {
                        AddArticleCallback(SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.Get(i));
                    }
                }
            }
            LoadListBoxCallback();
            UpdateListBoxCallback2(true);
        }

        private void UpdateStarredArticles(Object stateInfo)
        {
            ClearCallback(true);
            for (int i = 0; i < SpeeedReader.starred.Count; i++)
            {
                SpeeedReader.starred.Get(i).index = i;
                AddArticleCallback2(SpeeedReader.starred.Get(i));
            }
            LoadListBoxCallback();
            UpdateListBoxCallback2(true);
        }

        private void UpdateBroadcastArticles(Object stateInfo)
        {
            ClearCallback(true);
            for (int i = 0; i < SpeeedReader.shared.Count; i++)
            {
                SpeeedReader.shared.Get(i).index = i;
                AddArticleCallback2(SpeeedReader.shared.Get(i));
            }
            LoadListBoxCallback();
            UpdateListBoxCallback2(true);
        }

        /// <summary>
        /// Populates the list with tags
        /// </summary>
        /// <param name="stateInfo"></param>
        private void PopulateWithTags(Object stateInfo)
        {
            ToggleMainListBox(false);
            if (!_is_ui_processing)
            {
                _is_ui_processing = true;
                if (SpeeedReader.tags.Count > 0)
                {
                    ClearCallback(true);
                    ToggleMarkMenuCallback(false);
                    //adds tags to listbox
                    for (int i = 0; i < SpeeedReader.tags.Count; i++)
                    {
                        SpeeedReader.tags.Get(i).index = i;
                        AddTagCallback(SpeeedReader.tags.Get(i));
                    }
                    //if we are coming from subscriptions reload the current tag page
                    if (_going_back)
                    {
                        _page = _tag_page;
                        _going_back = false;
                    }
                    ToggleSubtextCallback(false);
                    LoadListBoxCallback();
                    UpdateStatusLabelCallback("Tags");
                    if (_currently_viewing > 0)
                    {
                        UpdateListBoxCallback(true);
                    }
                    else
                    {
                        UpdateListBoxCallback(false);
                    }
                    _currently_viewing = view_state.tags;
                    ToggleCheckItem();
                    ToggleBackButtonCallback();
                }
                _is_ui_processing = false;
            }
            ToggleMainListBox(true);
        }

        /// <summary>
        /// Populates the list with subscriptions
        /// </summary>
        /// <param name="stateInfo"></param>
        private void PopulateWithSubscriptions(Object stateInfo)
        {
            ToggleMainListBox(false);
            if (!_is_ui_processing)
            {
                _is_ui_processing = true;
                Tag tag = SpeeedReader.tags.Get(_tag_index);
                if (tag.subscriptions.Count > 0)
                {
                    //save current page if current forward
                    if (!_going_back)
                    {
                        _tag_page = _page;
                    }
                    ClearCallback(true);
                    ToggleMarkMenuCallback(false);
                    for (int i = 0; i < tag.subscriptions.Count; i++)
                    {
                        SpeeedReader.tags.Get(_tag_index).subscriptions.Get(i).index = i;
                        AddSubscriptionCallback(SpeeedReader.tags.Get(_tag_index).subscriptions.Get(i));
                    }
                    //if we are coming from articles reload the current tag page
                    if (_going_back)
                    {
                        _page = _sub_page;
                        _going_back = false;
                    }
                    ToggleSubtextCallback(false);
                    LoadListBoxCallback();
                    UpdateStatusLabelCallback(tag.name);
                    if (_currently_viewing == view_state.articles || _currently_viewing == view_state.tag_reading)
                    {
                        UpdateListBoxCallback(true);
                    }
                    else
                    {
                        UpdateListBoxCallback(false);
                    }
                    _currently_viewing = view_state.subscriptions;
                    ToggleBackButtonCallback();
                }
                _is_ui_processing = false;
            }
            ToggleMainListBox(true);
        }

        /// <summary>
        /// Populates the screen with articles from the main reading list
        /// </summary>
        /// <param name="stateInfo"></param>
        private void PopulateWithReadingListArticles(object stateInfo)
        {
            ToggleMainListBox(false);
            if (!_is_ui_processing)
            {
                _is_ui_processing = true;
                if (SpeeedReader.reading == null)
                {
                    ToggleWaitCursorCallback(true);
                    SpeeedReader.RefreshReadingList(_first_refresh_run);
                }
                if (SpeeedReader.reading.Count > 0)
                {
                    ClearCallback(true);
                    _currently_viewing = view_state.reading;
                    ToggleMarkMenuCallback(true);
                    for (int i = 0; i < SpeeedReader.reading.Count; i++)
                    {
                        SpeeedReader.reading.Get(i).index = i;
                        AddArticleCallback2(SpeeedReader.reading.Get(i));
                    }
                    ToggleSubtextCallback(true);
                    LoadListBoxCallback();
                    ToggleWaitCursorCallback(false);
                    UpdateStatusLabelCallback("Reading List");
                    UpdateListBoxCallback(false);
                    ToggleCheckItem();
                    ToggleBackButtonCallback();
                }
                else
                {
                    ToggleWaitCursorCallback(false);
                    DisplayMessageBox("There are 0 articles to load");
                }
                _is_ui_processing = false;
            }
            ToggleMainListBox(true);
        }

        private void PopulateWithStarredArticles(object stateInfo)
        {
            ToggleMainListBox(false);
            if (!_is_ui_processing)
            {
                _is_ui_processing = true;
                if (SpeeedReader.starred == null)
                {
                    ToggleWaitCursorCallback(true);
                    SpeeedReader.RefreshStarredList();
                }
                if (SpeeedReader.starred.Count > 0)
                {
                    ClearCallback(true);
                    _currently_viewing = view_state.starred;
                    for (int i = 0; i < SpeeedReader.starred.Count; i++)
                    {
                        SpeeedReader.starred.Get(i).index = i;
                        AddArticleCallback2(SpeeedReader.starred.Get(i));
                    }
                    ToggleSubtextCallback(true);
                    LoadListBoxCallback();
                    ToggleWaitCursorCallback(false);
                    ToggleMarkMenuCallback(true);
                    UpdateStatusLabelCallback("Starred");
                    UpdateListBoxCallback(false);
                    ToggleCheckItem();
                    ToggleBackButtonCallback();
                }
                else
                {
                    ToggleWaitCursorCallback(false);
                    DisplayMessageBox("There are 0 articles to load");
                }
                _is_ui_processing = false;
            }
            ToggleMainListBox(true);
        }

        /// <summary>
        /// Populates the list with articles from the broadcast list
        /// </summary>
        /// <param name="stateInfo"></param>
        private void PopulateWithBroadcastArticles(object stateInfo)
        {
            ToggleMainListBox(false);
            if (!_is_ui_processing)
            {
                _is_ui_processing = true;
                if (SpeeedReader.shared == null)
                {
                    ToggleWaitCursorCallback(true);
                    SpeeedReader.RefreshSharedList();
                }
                if (SpeeedReader.shared.Count > 0)
                {
                    ClearCallback(true);
                    _currently_viewing = view_state.shared;
                    for (int i = 0; i < SpeeedReader.shared.Count; i++)
                    {
                        SpeeedReader.shared.Get(i).index = i;
                        AddArticleCallback2(SpeeedReader.shared.Get(i));
                    }
                    ToggleSubtextCallback(true);
                    LoadListBoxCallback();
                    ToggleWaitCursorCallback(false);
                    ToggleMarkMenuCallback(true);
                    UpdateStatusLabelCallback("Shared");
                    UpdateListBoxCallback(false);
                    ToggleCheckItem();
                    ToggleBackButtonCallback();
                }
                else
                {
                    ToggleWaitCursorCallback(false);
                    DisplayMessageBox("There are 0 articles to load");
                }
                _is_ui_processing = false;
            }
            ToggleMainListBox(true);
        }    

        /// <summary>
        /// Populates the list with articles from a subscription or tag reading list
        /// </summary>
        /// <param name="stateInfo"></param>
        private void PopulateWithArticles(object stateInfo)
        {
            ToggleMainListBox(false);
            if (!_is_ui_processing)
            {
                _is_ui_processing = true;
                Subscription sub = SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index);
                if (!sub.articles_loaded)
                {
                    ToggleWaitCursorCallback(true);
                    if (Settings.offline_mode_enabled && SpeeedReader.DoesCacheExist())
                    {
                        SpeeedReader.tags.Get(_tag_index).subscriptions.Set(_sub_index, SpeeedReader.ImportSubscription(sub.title));
                    }
                    else if (!Settings.offline_mode_enabled)
                    {
                        if (Settings.caching_enabled && SpeeedReader.DoesCacheExist())
                        {
                            Subscription imported = SpeeedReader.ImportSubscription(sub.title);
                            //if imported == null, then must be a new sub (or doesnt exist) act accordingly
                            if (imported != null)
                            {
                                SpeeedReader.tags.Get(_tag_index).subscriptions.Set(_sub_index, imported);
                                SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshArticles(false);
                            }
                            else
                            {
                                SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshArticles(true);
                            }
                        }
                        else
                        {
                            SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshArticles(true);
                        }
                    }
                    SpeeedReader.tags.Get(_tag_index).RefreshUnreadCount();
                }
                if (SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles_loaded)
                {
                    //save current page if going forward
                    if (!_going_back)
                    {
                        _sub_page = _page;
                    }
                    ToggleMarkMenuCallback(true);
                    ClearCallback(true);
                    for (int i = 0; i < SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.Count; i++)
                    {
                        //SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).last_access = DateTime.Now;
                        SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.Get(i).index = i;
                        //if article is from a tag reading list    
                        if (SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).is_reading_list)
                        {
                            AddArticleCallback2(SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.Get(i));
                            _currently_viewing = view_state.tag_reading;
                        }
                        //if not
                        else
                        {
                            AddArticleCallback(SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.Get(i));
                            _currently_viewing = view_state.articles;
                        }
                    }
                    ToggleSubtextCallback(true);
                    LoadListBoxCallback();
                    ToggleWaitCursorCallback(false);
                    UpdateStatusLabelCallback(sub.title);
                    UpdateListBoxCallback(false);
                    ToggleBackButtonCallback();
                }
                else
                {
                    ToggleWaitCursorCallback(false);
                    DisplayMessageBox("There are 0 articles to load");
                    SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles = null;
                }
                _is_ui_processing = false;
            }
            ToggleMainListBox(true);
        }       

        private void BackAction(object sender, EventArgs e)
        {
            switch (_currently_viewing)
            {
                case view_state.tags:
                    //do nothing
                    break;
                case view_state.subscriptions:
                    _going_back = true;
                    ThreadFactory.DoWork(PopulateWithTags);
                    _page = 0;
                    break;
                case view_state.articles:
                    _going_back = true;
                    ThreadFactory.DoWork(PopulateWithSubscriptions);
                    _page = 0;
                    break;
                case view_state.reading:
                    ThreadFactory.DoWork(PopulateWithTags);
                    _page = 0;
                    break;
                case view_state.browser:
                    CloseBrowserCallback(null);
                    menuItem_search.Enabled = menuItem_view.Enabled = true;                    
                    if (menuItem_show_reading_list.Checked)
                        _currently_viewing = view_state.reading;
                    else if (menuItem_show_starred.Checked)
                        _currently_viewing = view_state.starred;
                    else if (menuItem_show_broadcast.Checked)
                        _currently_viewing = view_state.shared;
                    else if (SpeeedReader.tags.Get(_tag_index).subscriptions.
                        Get(_sub_index).is_reading_list && menuItem_show_tags.Checked)
                        _currently_viewing = view_state.tag_reading;
                    else if (menuItem_show_tags.Checked)
                        _currently_viewing = view_state.articles;
                    else
                        _currently_viewing = view_state.search;
                    main_listBox.Refresh();
                    break;                        
                case view_state.starred:
                    ThreadFactory.DoWork(PopulateWithTags);
                    _page = 0;
                    break;
                case view_state.shared:
                    ThreadFactory.DoWork(PopulateWithTags);
                    _page = 0;
                    break;
                case view_state.tag_reading:
                    ThreadFactory.DoWork(PopulateWithSubscriptions);
                    _page = 0;
                    break;
                case view_state.search:
                    SpeeedReader.search_results = null;
                    ThreadFactory.DoWork(PopulateWithTags);
                    _page = 0;
                    break;
                default:
                    break;
            }            
        }

        /// <summary>
        /// Marks items in memory as read
        /// </summary>
        /// <param name="index"></param>
        private void MarkAllSubscriptionsAsRead(int index)
        {
            ToggleWaitCursorCallback(true);
            for (int i = 0; i < SpeeedReader.tags.Get(index).subscriptions.Count; i++)
            {
                if (!SpeeedReader.tags.Get(index).subscriptions.Get(i).articles_loaded)
                {
                    SpeeedReader.tags.Get(index).subscriptions.Get(i).unread_count = 0;
                }
                else
                {
                    SpeeedReader.tags.Get(index).subscriptions.Get(i).articles.MarkAllArticlesRead();                    
                }
                SpeeedReader.tags.Get(index).subscriptions.Get(i).RefreshUnreadCount();
            }
            SpeeedReader.tags.Get(index).RefreshUnreadCount();
            ToggleWaitCursorCallback(false);
        }

        /// <summary>
        /// Marks all tags in memory as read
        /// </summary>
        /// <param name="index"></param>
        private void MarkAllArticlesAsRead(int index)
        {
            if (!SpeeedReader.tags.Get(_tag_index).subscriptions.Get(index).articles_loaded)
            {
                SpeeedReader.tags.Get(_tag_index).subscriptions.Get(index).unread_count = 0;
            }
            else
            {
                SpeeedReader.tags.Get(_tag_index).subscriptions.Get(index).articles.MarkAllArticlesRead();
            }
            SpeeedReader.tags.Get(_tag_index).subscriptions.Get(index).RefreshUnreadCount();
            SpeeedReader.tags.Get(_tag_index).RefreshUnreadCount();
        }

        /// <summary>
        /// Marks all items in memory with a given tag as read
        /// </summary>
        /// <param name="stateInfo"></param>
        private void MarkTagItemAsRead(Object stateInfo)
        {            
            if (_art_index > -1)
            {
                //viewing list of tags, mark the selected tag as read
                MarkAllSubscriptionsAsRead(_art_index);              
            }            
            else
            {
                ToggleWaitCursorCallback(true);
                //viewing list of tags, no tag is selected, then we want to mark all the tags as read
                for (int i = 0; i < SpeeedReader.tags.Count; i++)
                {
                    if (!SpeeedReader.tags.Get(i).google_tag && SpeeedReader.tags.Get(i).name != "Untagged")
                    {
                        MarkAllSubscriptionsAsRead(i);
                    }
                }
                ToggleWaitCursorCallback(false);
            }
            UpdateTags(String.Empty);
            FocusListBoxCallback();
        }

        private void RefreshProcess(Object stateInfo)
        {            
            RefreshAll();
        }

        /// <summary>
        /// Marks all articles under a subscription in memory as read
        /// </summary>
        /// <param name="stateInfo"></param>
        private void MarkSubItemAsRead(Object stateInfo)
        {
            //ToggleWaitCursorCallback(true);
            if (_art_index > -1)
            {
                //viewing list of subscriptions, mark the selected subscription as read
                MarkAllArticlesAsRead(_art_index);                
            }
            else
            {            
                //viewing list of subscriptions, no subscription is selected then mark the tag as read
                MarkAllSubscriptionsAsRead(_tag_index);                
            }
            UpdateSubscriptions(String.Empty);
            FocusListBoxCallback();
            //ToggleWaitCursorCallback(false);
        }

        /// <summary>
        /// Marks tag as read in Google reader server
        /// </summary>
        /// <param name="stateInfo"></param>
        private void MarkTagAsRead(Object stateInfo)
        {
            if (_art_index > -1)
            {                
                SpeeedReader.MarkAllAsRead(SpeeedReader.tags.Get(_art_index).id,
                                SpeeedReader.tags.Get(_art_index).name);
            }
            else
            {
                for (int i = 0; i < SpeeedReader.tags.Count; i++)
                {
                    if (!SpeeedReader.tags.Get(i).google_tag && SpeeedReader.tags.Get(i).name != "Untagged")
                    {
                        SpeeedReader.MarkAllAsRead(SpeeedReader.tags.Get(i).id,
                                    SpeeedReader.tags.Get(i).name);
                    }                                       
                }
            }          
        }

        /// <summary>
        /// Marks subscription as read in google reader server
        /// </summary>
        /// <param name="stateInfo"></param>
        private void MarkSubAsRead(Object stateInfo)
        {           
            if (_art_index > -1)
            {
                SpeeedReader.MarkAllAsRead(SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_art_index).id,
                                SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_art_index).title);                
            }
            else
            {
                if (SpeeedReader.tags.Get(_tag_index).name != "Untagged")
                {
                    SpeeedReader.MarkAllAsRead(SpeeedReader.tags.Get(_tag_index).id,
                                    SpeeedReader.tags.Get(_tag_index).name);
                }
            }            
        }

        /// <summary>
        /// Marks article as read in memory
        /// </summary>
        /// <param name="stateInfo"></param>
        private void MarkArticleAsRead(Object stateInfo)
        {
            if (_art_index > -1)
            {
                SpeeedReader.tags.Get(_tag_index).subscriptions.
                    Get(_sub_index).articles.Get(_art_index).unread = false;
                MarkArticleItemRead(_art_index);
                SpeeedReader.MarkItemRead(SpeeedReader.tags.Get(_tag_index).subscriptions.
                    Get(_sub_index).articles.Get((_page * Settings.page_size) + _art_index).id);
                UpdateListBoxCallback2(true);         
            }
            else
            {
                ToggleWaitCursorCallback(true);
                SpeeedReader.MarkAllAsRead(SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).id,
                                SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).title);
                SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.MarkAllArticlesRead();
                UpdateArticles(String.Empty);
                ToggleWaitCursorCallback(false);
            }
            SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshUnreadCount();
            SpeeedReader.tags.Get(_tag_index).RefreshUnreadCount();
            FocusListBoxCallback();
        }

        /// <summary>
        /// Changes the icon from unread to read on the list
        /// </summary>
        /// <param name="index"></param>
        private void MarkArticleItemRead(int index)
        {
            main_listBox.Items[index].ItemIconAlpha = GetIcon(icon_type.read_art);
            //UpdateListBox2Callback();
        }

        /// <summary>
        /// Marks an article on the Google Reader server as read
        /// </summary>
        /// <param name="stateInfo"></param>
        private void MarkArticleRead(Object stateInfo)
        {
            if (menuItem_show_reading_list.Checked)
            {
                SpeeedReader.MarkItemRead(SpeeedReader.reading.Get(_art_index).id);
            }
            else if (menuItem_show_tags.Checked)
            {
                SpeeedReader.MarkItemRead(SpeeedReader.tags.Get(_tag_index).subscriptions.
                    Get(_sub_index).articles.Get(_art_index).id);
            }
            else
            {
                SpeeedReader.MarkItemRead(SpeeedReader.search_results.Get(_art_index).id);
            }

            SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshUnreadCount();
            SpeeedReader.tags.Get(_tag_index).RefreshUnreadCount();
        }

        private void MarkStoredArticleRead(Object article_id)
        {
            if (SpeeedReader.tags.GetArticleByID((string)article_id) != null)
            {
                SpeeedReader.tags.GetArticleByID((string)article_id).unread = false;
            }
        }

        private void MarkStoredArticleStar(object stateInfo)
        {
            if (SpeeedReader.tags.GetArticleByID((string)stateInfo) != null)
            {
                SpeeedReader.tags.GetArticleByID((string)stateInfo).starred = true;
            }
            SpeeedReader.MarkItemStarred(stateInfo);
        }

        private void MarkStoredArticleUnread(object stateInfo)
        {
            if (SpeeedReader.tags.GetArticleByID((string)stateInfo) != null)
            {
                SpeeedReader.tags.GetArticleByID((string)stateInfo).unread = true;
            }
            SpeeedReader.MarkArticleUnread(stateInfo);
        }

        private void ChangePage(Object stateInfo)
        {
            ClearCallback(false);
            LoadListBoxCallback();
            UpdateListBoxCallback2(false);
        }

        private void DownloadMoreArticles(Object stateInfo)
        {
            ToggleWaitCursorCallback(true);
            Articles more_articles = null;
            if (SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).is_reading_list)
            {
                more_articles = SpeeedReader.GetMoreTagArticles(
                        SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.continuation,
                        SpeeedReader.tags.Get(_tag_index).name);
            }
            else
            {
                more_articles = SpeeedReader.GetMoreFeedArticles(
                        SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.continuation,
                        SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).id);
            }
            int list_size = SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.Count;
            SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.Add(more_articles, true, false);
            SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).RefreshUnreadCount();
            for (int i = 0; i < more_articles.Count; i++)
            {
                more_articles.Get(i).index = list_size + i;
                if (more_articles.Get(i).unread)
                {
                    if (_currently_viewing == view_state.tag_reading)
                    {
                        _list_items.Add(GetArticleItem2(more_articles.Get(i)));
                    }
                    else
                    {
                        _list_items.Add(GetArticleItem(more_articles.Get(i)));
                    }
                }
                else if (!more_articles.Get(i).unread && !Settings.hide_read_items)
                {
                    if (_currently_viewing == view_state.tag_reading)
                    {
                        _list_items.Add(GetArticleItem2(more_articles.Get(i)));
                    }
                    else
                    {
                        _list_items.Add(GetArticleItem(more_articles.Get(i)));
                    }
                }
            }
            SpeeedReader.tags.Get(_tag_index).subscriptions.Get(_sub_index).articles.continuation =
                more_articles.continuation;
            ChangePage(null);
            ToggleWaitCursorCallback(false);
        }

        private void CreateSms(Object stateInfo)
        {
            ToggleWaitCursorCallback(true);
            string[] info = (string[])stateInfo;
            string message = WebManager.ShortenUrl(info[0]);
            ToggleWaitCursorCallback(false);
            MsgEngine msg_engine = new MsgEngine();
            msg_engine.CreateSMS(info[1], message);
        }

        private void CreateEmail(Object stateInfo)
        {
            ToggleWaitCursorCallback(true);
            string[] info = (string[])stateInfo;
            string message = WebManager.ShortenUrl(info[0]);
            ToggleWaitCursorCallback(false);
            MsgEngine msg_engine = new MsgEngine();
            msg_engine.CreateEmail(info[1], message);
        }


        public void SearchArticles(Object stateInfo)
        {
            ToggleWaitCursorCallback(true);            
            ClearCallback(true);            
            string search_string = (string)stateInfo;
            string[] search = null;
            if (search_string.Contains(','))
            {
                search = search_string.Split(',');
            }
            else
            {
                search = new string[] { search_string };
            }

            SpeeedReader.search_results = new Articles();
            //search for the article with the search term
            for (int i = 0; i < SpeeedReader.tags.Count; i++)
            {
                for (int j = 0; j < SpeeedReader.tags.Get(i).subscriptions.Count; j++)
                {
                    if(SpeeedReader.tags.Get(i).subscriptions.Get(j).articles_loaded && !SpeeedReader.tags.Get(i).subscriptions.Get(j).is_reading_list)
                    {
                        for (int k = 0; k < SpeeedReader.tags.Get(i).subscriptions.Get(j).articles.Count; k++)
                        {
                            for (int l = 0; l < search.Length; l++)
                            {
                                Article article = SpeeedReader.tags.Get(i).subscriptions.Get(j).articles.Get(k);
                                if (article.title.ToLower().Contains(search[l].ToLower().Trim()) ||
                                    article.summary.ToLower().Contains(search[l].ToLower().Trim()) ||
                                    article.site_name.ToLower().Contains(search[l].ToLower().Trim()))
                                {
                                    SpeeedReader.search_results.Add(article);
                                    break;
                                }
                            }
                        }
                    }
                }
            }                  
            if (SpeeedReader.search_results.Count > 0)
            {
                if (SpeeedReader.search_results.Count > Settings.search_results_size)
                {
                    SpeeedReader.search_results = SpeeedReader.search_results.GetRange(Settings.search_results_size);
                }
                SpeeedReader.search_results.Sort();
                //now add the articles to the listbox
                for (int i = 0; i < SpeeedReader.search_results.Count; i++)
                {
                    SpeeedReader.search_results.Get(i).index = i;
                    AddArticleCallback2(SpeeedReader.search_results.Get(i));
                }
                ToggleSubtextCallback(true);
                LoadListBoxCallback();                
            }
            else
            {
                DisplayMessageBox("0 articles found");
            }
            ToggleWaitCursorCallback(false);
            ToggleMarkMenuCallback(true);
            UpdateStatusLabelCallback(SpeeedReader.search_results.Count + " articles found");
            UpdateListBoxCallback2(false);
            FocusListBoxCallback();
        }

        #endregion

        #region user interface callbacks

        private void ToggleCachingMenuCallback(bool enable)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _toggleCachingMenuDelegate(ToggleCachingMenuCallback), enable);
            }
            else
            {
                menuItem_caching.Enabled = enable;
            }
        }

        private void ToggleMainListBox(bool enable)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _toggleMainListBoxDelegate(ToggleMainListBox), enable);
            }
            else
            {
                main_listBox.Enabled = enable;
                main_listBox.Focus();
            }            
        }

        private void FocusListBoxCallback()
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _focusListBoxDelegate(FocusListBoxCallback));
            }
            else
            {
                main_listBox.Focus();
            }
        }

        private void ToggleBackButtonCallback()
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _toggleBackButtonDelegate(ToggleBackButtonCallback));
            }
            else
            {
                if (_currently_viewing == view_state.tags)
                {
                    menuItem_back.Enabled = false;
                }
                else
                {
                    menuItem_back.Enabled = true;
                }
                if (!webBrowser_article.Visible)
                {
                    main_listBox.Focus();
                }
            }
        }

        private void ToggleSubtextCallback(bool enable)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _toggleSubtextDelegate(ToggleSubtextCallback), enable);
            }
            else
            {
                if (enable)
                {
                    main_listBox.ShowSubText = true;
                    main_listBox.Font = new System.Drawing.Font("Tahoma", 8F, System.Drawing.FontStyle.Bold);
                }
                else
                {
                    main_listBox.ShowSubText = false;
                    if (!Settings.use_smaller_list_font)
                    {
                        main_listBox.Font = new System.Drawing.Font("Tahoma", 10F, System.Drawing.FontStyle.Regular);
                    }
                }
            }
        }

        public void UpdateRefreshLabelCallback(string progress)
        {
            if (label_refresh_status.InvokeRequired)
            {
                label_refresh_status.Invoke(new _updateRefreshLabel(UpdateRefreshLabelCallback), progress);
            }
            else
            {
                label_refresh_status.Text = progress;                
            }
        }

        public void ToggleRefresh(bool enable)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new _toggleRefresh(ToggleRefresh), enable);
            }
            else
            {
                if (enable)
                {
                    menuItem_refresh.Text = "Refresh";
                }
                else
                {
                    menuItem_refresh.Text = "Cancel Refresh";
                }
            }
        }

        public void UpdateStatusLabelCallback(string title)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new _updateStatusLabelCallback(UpdateStatusLabelCallback), title);
            }
            else
            {                
                label_program_status.Text = title;
            }
        }

        public void UpdateListBoxCallback2(bool keep_selection)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _updateListBoxCallback2(UpdateListBoxCallback2), keep_selection);
            }
            else
            {
                try
                {
                    if (main_listBox.SelectedIndex < main_listBox.Items.Count)
                    {
                        main_listBox.UpdateList(keep_selection);
                    }
                    else
                    {
                        main_listBox.UpdateList(false);
                    }
                }
                catch (Exception e)
                {

                }
            }
        }

        public void UpdateListBoxCallback(bool goingBack)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _updateListBoxCallback(UpdateListBoxCallback), goingBack);
            }
            else
            {
                try
                {
                    main_listBox.UpdateList();                    
                    main_listBox.Focus();
                }
                catch (Exception e)
                {
                }
            }
        }      

        private void ToggleWaitCursorCallback(bool enable)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new _toggleWaitCursorCallback(ToggleWaitCursorCallback), enable);
            }
            else
            {
                main_listBox.Enabled = !enable;
                if (enable)
                {
                    Cursor.Current = Cursors.WaitCursor;
                }
                else
                {
                    Cursor.Current = Cursors.Default;
                }
            }
        }

        private void AddTagCallback(Tag info)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _addTagCallback(
                    AddTagCallback), info);
            }
            else
            {
                _list_items.Add(GetTagItem(info));
            }
        }

        private void AddSubscriptionCallback(Subscription info)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _addSubscriptionCallback(
                    AddSubscriptionCallback), info);
            }
            else
            {
                if (info.unread_count > 0 || info.is_reading_list || Settings.offline_mode_enabled)
                {
                    _list_items.Add(GetSubscriptionItem(info));
                }
                else if (!(info.unread_count > 0) && !Settings.hide_read_items)
                {
                    _list_items.Add(GetSubscriptionItem(info));
                }
                
            }
        }

        private void AddArticleCallback(Article info)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _addArticleCallback(
                    AddArticleCallback), info);
            }
            else
            {
                try
                {
                    if (info.unread)
                    {
                        _list_items.Add(GetArticleItem(info));
                    }
                    else if (!info.unread && !Settings.hide_read_items)
                    {
                        _list_items.Add(GetArticleItem(info));
                    }
                }
                catch (Exception e)
                {

                }
            }
        }

        private void AddArticleCallback2(Article info)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _addArticleCallback2(
                    AddArticleCallback2), info);
            }
            else
            {
                try
                {
                    if (info.unread || _currently_viewing == view_state.shared || _currently_viewing == view_state.starred
                        || _currently_viewing == view_state.search)
                    {
                        _list_items.Add(GetArticleItem2(info));
                    }
                    else if(!info.unread && !Settings.hide_read_items)
                    {
                        _list_items.Add(GetArticleItem2(info));
                    }
                }
                catch (Exception e)
                {

                }
            }
        }
     
        private void ToggleMarkMenuCallback(bool enable)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _toggleStarArticleCallback(
                    ToggleMarkMenuCallback), enable);
            }
            else
            {
                if (!Settings.offline_mode_enabled)
                {
                    menuItem_mark_unread.Enabled = enable;
                    menuItem_star.Enabled = enable;
                    menuItem_share.Enabled = enable;
                    menuItem_open_in_browser.Enabled = enable;
                }
            }
        }

        /// <summary>
        /// Loads the browser and displays html
        /// </summary>
        /// <param name="html"></param>
        private void ShowBrowserCallback(Object stateInfo)
        {
            if (webBrowser_article.InvokeRequired)
            {
                webBrowser_article.Invoke(new _openBrowserCallback(ShowBrowserCallback), String.Empty);
            }
            else
            {
                main_listBox.Hide();
                webBrowser_article.Show();
                webBrowser_article.Visible = true;
                webBrowser_article.BringToFront();
                webBrowser_article.DocumentText = _t_html;
                webBrowser_article.Focus();
            }
        }

        private void CloseBrowserCallback(Object stateInfo)
        {
            if (webBrowser_article.InvokeRequired)
            {
                webBrowser_article.Invoke(new _closeBrowserCallback(CloseBrowserCallback),String.Empty);
            }
            else
            {
                UpdateListBoxCallback2(false);
                main_listBox.SelectedIndex = _selected_index;
                main_listBox.Show();
                webBrowser_article.Visible = false;
                webBrowser_article.SendToBack();
                webBrowser_article.Url = null;
                webBrowser_article.DocumentText = _t_html = null;
                webBrowser_article.Clear();
                main_listBox.Focus();               
            }
        }

        private void LoadListBoxCallback()
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new  _loadListBoxCallback(LoadListBoxCallback));
            }
            else
            {
                //calculate the number of max number of pages
                _max_pages = _list_items.Count / Settings.page_size;
                if ((_list_items.Count % Settings.page_size) > 0 || _max_pages == 0)
                {
                    _max_pages++;
                }
                //if there is a previous page, add previous page button
                if (_page > 0)
                {
                    main_listBox.Items.Add(GetListNavItem("   <-- Go to Page " + (_page)));
                }
                int number_items_left = _list_items.Count - _page * Settings.page_size;
                List<TouchListBox.TouchListItem> temp_list = null;
                //not last page of items
                if (number_items_left < Settings.page_size)
                {
                    temp_list = _list_items.GetRange(_page * Settings.page_size, number_items_left);
                }
                //last page of items
                else
                {
                    temp_list = _list_items.GetRange(_page * Settings.page_size, Settings.page_size);
                }

                main_listBox.Items.AddRange(temp_list);
                //if NOT the last page, add next page button
                if (_page < (_max_pages - 1))
                {
                    main_listBox.Items.Add(GetListNavItem("   Go to Page " + (_page + 2) + " -->"));
                }
                //if on the last page of articles && not hiding read articles, add the download more button
                else if (_page == _max_pages - 1 && (_currently_viewing == view_state.articles || _currently_viewing == view_state.tag_reading) &&
                    menuItem_star.Enabled && /*Settings.download_read_articles &&*/ !Settings.offline_mode_enabled)
                {
                    main_listBox.Items.Add(GetListNavItem("   Download More Articles"));
                }
                main_listBox.Items.TrimExcess();
                //main_listBox.Focus();
            }            
        }

        private void ClearCallback(bool all_lists)
        {
            if (main_listBox.InvokeRequired)
            {
                main_listBox.Invoke(new _clearCallback(ClearCallback), all_lists);
            }
            else
            {
                if (all_lists)
                {
                    _list_items.Clear();
                    _page = 0;
                }
                main_listBox.Items.Clear();
            }
        }

        private string ProcessHTML(string html)
        {
            if (Settings.download_images && !Settings.offline_mode_enabled)
            {
                return html;
            }
            else
            {
                while (html.Contains("<img"))
                {
                    int start = html.IndexOf("<img");
                    int end = html.IndexOf(">", start + 1) + 1;
                    html = html.Remove(start, end - start);
                }
                return html;
            }
        }

        private void ToggleCheckItem()
        {
            if(this.InvokeRequired)
            {
                this.Invoke(new _toggleCheckItem(ToggleCheckItem));
            }
            else
            {
                switch(_currently_viewing)
                {
                    case view_state.tags:
                        menuItem_show_starred.Checked = menuItem_show_reading_list.Checked =
                            menuItem_show_broadcast.Checked = false;
                        menuItem_show_tags.Checked = true;
                        break;         
                    case view_state.reading:
                        menuItem_show_starred.Checked = menuItem_show_tags.Checked =
                            menuItem_show_broadcast.Checked = false;
                        menuItem_show_reading_list.Checked = true;
                        break;
                    case view_state.starred:
                        menuItem_show_tags.Checked = menuItem_show_reading_list.Checked =
                            menuItem_show_broadcast.Checked = false;
                        menuItem_show_starred.Checked = true;
                        break;
                    case view_state.shared:
                        menuItem_show_starred.Checked = menuItem_show_reading_list.Checked =
                            menuItem_show_tags.Checked = false;
                        menuItem_show_broadcast.Checked = true;
                        break;
                    case view_state.search:
                        menuItem_show_starred.Checked = menuItem_show_reading_list.Checked =
                            menuItem_show_tags.Checked = menuItem_show_broadcast.Checked = false;
                        break;
                    default:
                        break;
                }
            }
        }

        private string[] GetArticleInfoToShare()
        {
            string[] article_info = new string[2]{ArticleFromView().url, ArticleFromView().title};           
            return article_info;
        }

        public void ToggleOfflineModeForm(bool connect)        
        {
            menuItem_refresh.Enabled = menuItem_view.Enabled = menuItem_share.Enabled = 
                menuItem_mark.Enabled = menuItem_update.Enabled = !Settings.offline_mode_enabled;
            if (connect)
            {
                SpeeedReader.SetCredentials();
            }
            if (Settings.offline_mode_enabled)
            {
                UpdateRefreshLabelCallback("Offline");
            }
            else
            {
                UpdateRefreshLabelCallback("Online");
            }
        }

        public void Login(Object stateInfo)
        {
            ToggleWaitCursorCallback(true);
            bool result = SpeeedReader.Login(new string[2] { Settings.username, Settings.password });
            ToggleWaitCursorCallback(false);
            if (result)
            {
                DisplayMessageBox("Now online");
            }
            else
            {
                DisplayMessageBox("Unable to go online");
            }
        }

        #endregion

        #region logic generating buttons representing articles, tags, etc 

        private AlphaImageClass.IImage GetIcon(icon_type icon)
        {
            switch (icon)
            {
                case icon_type.unread_tag:
                    if (Settings.item_size == 0) return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.unread_tag_icon_s);
                    else return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.unread_tag_icon);
                case icon_type.read_tag:
                    if (Settings.item_size == 0) return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.read_tag_icon_s);
                    else return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.read_tag_icon);
                case icon_type.sub:
                    if (Settings.item_size == 0) return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.sub_icon_s);
                    else return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.sub_icon);
                case icon_type.unread_art:
                    if (Settings.item_size == 0) return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.unread_icon_s);
                    else return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.unread_icon);
                case icon_type.read_art:
                    if (Settings.item_size == 0) return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.read_icon_s);
                    else return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.read_icon);
                case icon_type.star:
                    if (Settings.item_size == 0) return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.starred_icon_s);
                    else return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.starred_icon);
                default:
                    if (Settings.item_size == 0) return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.starred_icon_s);
                    else return AlphaImageClass.GetAlphaImageFromBytes(SpeeedReaderUI.Properties.Resources.starred_icon);
            }
        }

        /// <summary>
        /// Creates a label button with the given title
        /// </summary>
        /// <param name="title"></param>
        /// <returns></returns>
        private TouchListBox.TouchListItem GetTagItem(Tag info)
        {
            TouchListBox.TouchListItem ret_val = new TouchListBox.TouchListItem();            

            ret_val.Name = info.index.ToString();
            ret_val.Text = info.name;
            if (info.unread_count > 0)
            {
                ret_val.Text += " (" + info.unread_count + ")";
            }
            //if (!info.google_tag)
            //{
            //    ret_val.SubText = info.unread_count.ToString() + " unread article(s)";
            //}
            ret_val.ShowItemIcon = true;
            if (info.unread_count > 0)
            {
                ret_val.ItemIconAlpha = GetIcon(icon_type.unread_tag);
            }
            else
            {
                ret_val.ItemIconAlpha = GetIcon(icon_type.read_tag);
            }           

            return ret_val;
        }

        /// <summary>
        /// Creates a label button with the given title
        /// </summary>
        /// <param name="title"></param>
        /// <returns></returns>
        private TouchListBox.TouchListItem GetSubscriptionItem(Subscription info)
        {
            TouchListBox.TouchListItem ret_val = new TouchListBox.TouchListItem();

            ret_val.Name = info.index.ToString();
            ret_val.Text = info.title;
            if (info.unread_count > 0)
            {
                ret_val.Text += " (" + info.unread_count + ")";
            }
            //ret_val.SubText = info.unread_count + " unread article(s)";
            ret_val.ShowItemIcon = true;
            ret_val.ItemIconAlpha = GetIcon(icon_type.sub);
            return ret_val;
        }

        private TouchListBox.TouchListItem GetListNavItem(string title)
        {
            TouchListBox.TouchListItem ret_val = new TouchListBox.TouchListItem();
            
            ret_val.Name = String.Empty;
            ret_val.Text = title;
            ret_val.ShowItemIcon = false;

            return ret_val;
        }

        private TouchListBox.TouchListItem GetArticleItem(Article info)
        {
            TouchListBox.TouchListItem ret_val = new TouchListBox.TouchListItem();

            ret_val.Name = info.index.ToString();
            ret_val.Text = info.title;
            ret_val.SubText = info.date;
            ret_val.ShowItemIcon = true;
            if (!info.starred)
            {
                if (info.unread)
                {
                    ret_val.ItemIconAlpha = GetIcon(icon_type.unread_art);
                }
                else
                {
                    ret_val.ItemIconAlpha = GetIcon(icon_type.read_art);
                }
            }
            else
            {
                ret_val.ItemIconAlpha = GetIcon(icon_type.star);
            }
            
            return ret_val;
        }

        /// <summary>
        /// Get article item for reading list items
        /// </summary>
        /// <param name="info"></param>
        /// <returns></returns>
        private TouchListBox.TouchListItem GetArticleItem2(Article info)
        {
            TouchListBox.TouchListItem ret_val = new TouchListBox.TouchListItem();

            ret_val.Name = info.index.ToString();
            ret_val.Text = info.title;
            ret_val.SubText = info.site_name + ", " + info.date;
            ret_val.ShowItemIcon = true;
            if (!info.starred)
            {
                if (info.unread)
                {
                    ret_val.ItemIconAlpha = GetIcon(icon_type.unread_art);
                }
                else
                {
                    ret_val.ItemIconAlpha = GetIcon(icon_type.read_art);
                }
            }
            else
            {
                ret_val.ItemIconAlpha = GetIcon(icon_type.star);
            }

            return ret_val;
        }

        /// <summary>
        /// Displays message box with requested message and OK button
        /// </summary>
        /// <param name="message">message to display</param>
        public static void DisplayMessageBox(string message)
        {
            //MessageBox.Show(message, "Speeed Reader", MessageBoxButtons.OK, MessageBoxIcon.None, MessageBoxDefaultButton.Button1);
            GlassDialog.ShowDialog("Speeed Reader", message, "OK");
        }

        /// <summary>
        /// Displays message box with message and yes/no buttons
        /// </summary>
        /// <param name="message">message to display</param>
        /// <returns>which button was pressed</returns>
        public static int DisplayYesNoMessageBox(string message)
        {
            return GlassDialog.ShowDialog("Speeed Reader", message, "Yes", "No");
        }

        public static DialogResult DisplayOKMessageBox(string message)
        {
            return MessageBox.Show(message, "Speeed Reader", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
        }

        #endregion                         
       
    }

    public class TrustAllCertificatePolicy : System.Net.ICertificatePolicy
    {
        public TrustAllCertificatePolicy()
        { }

        public bool CheckValidationResult(ServicePoint sp,
         X509Certificate cert, WebRequest req, int problem)
        {
            return true;
        }
    }
}